#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <pthread.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <errno.h>
#include <semaphore.h>
#include <signal.h>
#include <assert.h>

// #define MAX_Thread_NUM 100
#define DEFAULT_ADD_NUM 5

struct Job
{
    void (*task)(void *arg); // 指向线程需要执行的具体任务
    void *arg;               // 线程传的参数

    struct Job *next;
};

struct thread_pool
{
    int min_thread_num; //创建线程池，初始化的线程个数
    int max_thread_num; //线程池最多容纳的线程数量

    int alive_thread_num;  //保存当前线程池中线程的数量
    int busy_thread_num;   //保存正在处理任务的线程梳理---计算空闲的线程
    int wait_exit_thread_num; //标记需要退出的线程的数量

    int queue_max_size; // 任务队列的最大值
    int queue_cur_size; // 任务队列的当前任务的个数

    pthread_t *ids;      //保存线程池中线程的id
    pthread_t manger_id; //管理线程的id
    pthread_mutex_t mutex;          // 线程池的锁
    pthread_mutex_t busy_mutex;     // 保护busy_thread_num：
    pthread_cond_t empty_queue;     // 等待任务队列空的条件
    pthread_cond_t not_empty_queue; // 等待任务队列非空
    pthread_cond_t not_full_queue;  // 等待任务队列非满队

    struct Job *font;
    struct Job *real;

    int pool_close;  // 线程池关闭：0  线程池运行：1
    int queue_close; // 任务队列是否可以操作的标志位；
};

struct thread_pool *pool;

/**
 * 1、入口参数检查
 * 2、检查任务队列是否开启；否：解锁，并退出
 * 3、检查任务队列是否为满队列？是：睡眠等待not_full_queue
 * 4、任务队列插入
 * 5、唤醒任务队列not_empty_queue;
 * 6、退出
 * */

void thread_add_job(struct thread_pool *pool, void (*task)(void *), void *arg)
{
    assert(pool != NULL);

    pthread_mutex_lock(&(pool->mutex));

    if (pool->queue_close == 1)
    {
        printf("thread task queue is close!\n");
        return;
    }
    // 任务队列满队--睡眠等待
    while (pool->queue_cur_size == pool->queue_max_size - 1)
    {
        pthread_cond_wait(&(pool->not_full_queue), &(pool->mutex));
    }

    if (pool->queue_close == 1)
    {
        printf("thread task queue is close!\n");
        return;
    }

    struct Job *new_job = (struct Job *)malloc(sizeof(struct Job));
    new_job->task = task;
    new_job->arg = arg;
    new_job->next = NULL;

    if (pool->font == NULL)
    {
        pool->font = new_job;
        pool->real = new_job;
    }
    else
    {
        pool->real->next = new_job;
        pool->real = new_job;
    }

    pool->queue_cur_size++;
    pthread_cond_broadcast(&(pool->not_empty_queue));

    pthread_mutex_unlock(&(pool->mutex));
}

/**
 * 1、入口参数检查
 * 2、上锁
 * 3、检查线程池和任务队列是否是开启状态；否：退出线程，并且释放锁！！
 * 4、检查任务队列中是否有任务？否：睡眠等待not_empty_queue;
 * 5、再次检查线程池是否开启？否：退出线程，并且释放锁！！ （释放线程池时，假唤醒）
 * 6、从任务队列中取任务
 * 7、对当前任务的数量减1，并且判断是否为0，如果为0，唤醒empty_queue(在释放线程池，等任务队列为空)，将任务队列置NULL；
 * 8、执行任务
 * 9、消耗任务
 * */
void *thread_function(void *arg)
{
    struct thread_pool *pool = (struct thread_pool *)arg;

    while (1)
    {
        // 判断线程池是否已经关闭；
        pthread_mutex_lock(&(pool->mutex));
        if ((pool->pool_close == 1) || (pool->queue_close == 1))
        {
            pthread_mutex_unlock(&(pool->mutex));
            printf("<<<<<<< thread %ld is exit! <<<< \n", pthread_self());
            pthread_exit(NULL);
        }

        // 判断任务队列是否为空
        while ((pool->queue_cur_size == 0) && (pool->queue_close != 1))
        {
            //所有空闲线程在没有任务处理的时候，都在此睡眠等待
            pthread_cond_wait(&(pool->not_empty_queue), &(pool->mutex));
            
            //将部分空闲线程退出
            if(pool->wait_exit_thread_num > 0)
            {
                for(int i = 0; i < pool->max_thread_num; i++)
                {
                    //pthread id == 0；
                    if(pool->ids[i] == pthread_self())
                    {
                        pool->ids[i] = 0;
                    }
                }
               
                pool->wait_exit_thread_num--;
                pool->alive_thread_num--;
                printf("thread pool total nums = %d\n", pool->alive_thread_num);
                pthread_mutex_unlock(&(pool->mutex));
                pthread_exit(NULL);
            }

            
        }

        // 为什么要再次判断线程池是否关闭？ 因为消耗线程池时，会进行假唤醒操作
        if (pool->pool_close == 1)
        {
            pthread_mutex_unlock(&(pool->mutex)); //!!!!!!
            printf("<<<<<<< thread %ld is exit! <<<< \n", pthread_self());
            pool->alive_thread_num--;
            pthread_exit(NULL);
        }

        // 从任务队列中取任务;
        struct Job *job = pool->font;
        pool->font = pool->font->next;
        pool->queue_cur_size--;
        // 当任务队列为空时，为什么要唤醒？ 消耗线程池时，在等待任务队列为空时，才进行销毁
        if (pool->queue_cur_size == 0)
        {
            pthread_cond_broadcast(&(pool->empty_queue));
            pool->font = NULL;
            pool->real = NULL;
        }

        pthread_cond_broadcast(&(pool->not_full_queue)); // 取任务队列，此时任务队列不为满队；
        pthread_mutex_unlock(&(pool->mutex));
        
        pthread_mutex_lock(&(pool->busy_mutex));
        pool->busy_thread_num++;
        pthread_mutex_unlock(&(pool->busy_mutex));
        
        job->task(job->arg); // 每个线程需要执行的任务:耗时

        free(job);
        job = NULL;

        pthread_mutex_lock(&(pool->busy_mutex));
        pool->busy_thread_num--;
        pthread_mutex_unlock(&(pool->busy_mutex));
      
        printf("task %ld is exit!\n", pthread_self());
    }
}

/**
 * 功能：判断id对应的线程是否存活
 * */
static int is_thread_alive(pthread_t id)
{
    int kill_rc = pthread_kill(id, 0);
    if (kill_rc == ESRCH)
    {
        return 1; // 线程不存在或已终止
    }
    else
    {
        return 0; // 线程存在
    }
}

/**
 * 功能：线程池的伸缩（定时检查）
 * 任务多，线程少：扩展当前任务个数大于最大值的一半
 * 空闲线程多：忙碌线程数量*4 < 总线程数
 * */
void *manger_thread_function(void *arg)
{
    struct thread_pool *pool = (struct thread_pool *)arg;
    assert(pool != NULL);

    while (pool->pool_close != 1)
    {
        sleep(5);
        pthread_mutex_lock(&(pool->mutex));
        // 任务多，线程少
        int add_thread_num = 0;
        if ((pool->queue_cur_size > (pool->queue_max_size / 2)) && (pool->alive_thread_num < pool->max_thread_num))
        {   
            printf(">>>>>>>> add thread num! <<<<<<<<<<<<!\n");
            for (int i = 0; (i < pool->max_thread_num) && (add_thread_num < DEFAULT_ADD_NUM); i++)
            {
                if ((pool->ids[i] == 0) || (is_thread_alive(pool->ids[i]) == 1))
                {
                    if (pthread_create(&(pool->ids[i]), NULL, thread_function, (void *)pool) < 0)
                    {
                        perror("thread create error!");
                        pthread_mutex_unlock(&(pool->mutex));
                        goto err;
                    }
                    pool->alive_thread_num++;
                    add_thread_num++;
                }
                 
                printf("thread pool total nums = %d\n", pool->alive_thread_num);
            }
        }
        // 线程多，任务少
        pthread_mutex_lock(&(pool->busy_mutex));
        int busy_num = pool->busy_thread_num;
        pthread_mutex_unlock(&(pool->busy_mutex));
        printf("busy num = %d\n", busy_num);
        if((busy_num * 4 < pool->alive_thread_num) && (pool->alive_thread_num > pool->min_thread_num) )
        {
            printf(">>>>>>>> remove thread num! <<<<<<<<<<<<!\n");
            pool->wait_exit_thread_num = DEFAULT_ADD_NUM;
            for(int i = 0; i < DEFAULT_ADD_NUM;  i++)
            {
                pthread_cond_signal(&(pool->not_empty_queue));  //唤醒次数和退出线程的数量一致
            }
        }
        pthread_mutex_unlock(&(pool->mutex));
    }
err:
    printf("manger thread is exit!\n");
    pthread_exit(NULL);
}

/**
 * 1、创建线程池
 * 2、初始化：线程池的线程数量、任务队列的最大值、任务队列当前数量、锁、各种条件变量
 * 3、初始化：给线程id分配空间；创建线程！！将线程池传递给每个线程函数
 * 4、！！！异常处理
 *
 * */
struct thread_pool *thread_pool_create(int min_num, int max_num, int queue_max_size)
{
    struct thread_pool *pool = (struct thread_pool *)malloc(sizeof(struct thread_pool));
    if (pool == NULL)
    {
        printf("pool malloc is error!\n");
        return NULL;
    }

    pool->min_thread_num = min_num;
    pool->max_thread_num = max_num;
    pool->alive_thread_num = min_num;
    pool->busy_thread_num = 0;

    pool->queue_max_size = queue_max_size;
    pool->queue_cur_size = 0;

    if (pthread_mutex_init(&(pool->mutex), NULL) != 0)
    {
        perror("thread pool mutex init error!");
        goto err;
    }
    
    if (pthread_mutex_init(&(pool->busy_mutex), NULL) != 0)
    {
        perror("thread pool busy mutex init error!");
        goto err;
    }

    if (pthread_cond_init(&(pool->not_empty_queue), NULL) != 0)
    {
        perror("thread pool cond not empty queue init error!");
        goto err;
    }

    if (pthread_cond_init(&(pool->not_full_queue), NULL) != 0)
    {
        perror("thread pool cond not full queue init error!");
        goto err;
    }

    if (pthread_cond_init(&(pool->empty_queue), NULL) != 0)
    {
        perror("thread pool cond empty queue init error!");
        goto err;
    }

    pool->font = NULL;
    pool->real = NULL;

    pool->queue_close = 0;
    pool->pool_close = 0;

    pool->ids = (pthread_t *)malloc(sizeof(pthread_t) * max_num);
    if (pool->ids == NULL)
    {
        printf("pthread ids malloc error!\n");
        goto err;
    }
    memset(pool->ids, 0, sizeof(pthread_t) * max_num);

    for (int i = 0; i < min_num; i++)
    {
        if (pthread_create(&(pool->ids[i]), NULL, thread_function, (void *)pool) < 0)
        {
            perror("thread create error!");
            goto err;
        }
    }

    if (pthread_create(&(pool->manger_id), NULL, manger_thread_function, (void *)pool) < 0)
    {
        perror("thread create  manger error!");
        goto err;
    }

    return pool;
err:
    free(pool);
    pool = NULL;
    return pool;
}

/**
 * 1、入口参数检查，上锁
 * 2、等待任务队列为空；
 * 3、关闭任务队列，关闭线程池
 * 4、假唤醒所有线程（not_empty_queue）
 * 5、等待所有线程退出，回收资源
 * 6、解锁
 * 7、释放锁、条件变量
 * 8、释放线程id容器
 * 9、释放任务队列
 * 10、释放线程池
 * */
void thread_pool_destory(struct thread_pool *pool)
{
    assert(pool != NULL);

    pthread_mutex_lock(&(pool->mutex));
    // 等任务队列全部处理结束
    while (pool->queue_cur_size != 0)
    {
        pthread_cond_wait(&(pool->empty_queue), &(pool->mutex));
    }

    // 不再允许任务队列添加新的任务
    pool->queue_close = 1;

    // 关闭线程池：让所有线程退出
    pool->pool_close = 1;

    pthread_cond_broadcast(&(pool->not_empty_queue));
    pthread_cond_broadcast(&(pool->not_full_queue));

    pthread_mutex_unlock(&(pool->mutex));
    for (int i = 0; i < pool->max_thread_num; i++)
    {
        printf("join thread exit>>>>>>!\n");
        pthread_join(pool->ids[i], NULL);
    }

    pthread_join(pool->manger_id, NULL);

    printf("all thread is exit!\n");

    pthread_mutex_destroy(&(pool->mutex));
    pthread_mutex_destroy(&(pool->busy_mutex));
    pthread_cond_destroy(&(pool->not_empty_queue));
    pthread_cond_destroy(&(pool->not_full_queue));
    pthread_cond_destroy(&(pool->empty_queue));
    free(pool->ids);
    while (pool->font != NULL)
    {
        struct Job *job = pool->font;
        free(job);
        pool->font = pool->font->next;
    }

    free(pool);
    pool = NULL;
}

void task(void *arg)
{
    int num = (int)(long)arg; 
    sleep(10);
    printf("thread %ld data = %d\n", pthread_self(), num);
}

void thread_exit(int sig)
{
    if (sig == SIGINT)
    {
        thread_pool_destory(pool);
        printf("thread pool is exit!\n");
        exit(1);
    }
}

/**
 * 多任务处理：
 * 1、进程：开销大/健壮 ------ 多少个进程？系统和硬件限制
 * 2、线程（进程的栈空间）：栈空间的大小
 * 3、IO多路转接(单线程)：局限IO多任务
 * 4、（主从式/分布式）多个IO多路 + 多线程（多进程）
*/


int main(int argc, char **argv)
{
    pool = thread_pool_create(5,30, 10000);

    signal(SIGINT, thread_exit);

    for (int i = 0; i < 10000; i++)
    {
        thread_add_job(pool, task, (void *)(long)i);
    }

    // sleep(10);

    // thread_pool_destory(pool);
    // printf("thread pool is exit!\n");

    pause();
    return 0;
}